package net.takela.acl.auth.filter;

import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import net.takela.acl.auth.AclProperties;
import net.takela.acl.auth.service.AclService;
import net.takela.acl.model.AclUser;
import net.takela.acl.model.UserRole;
import net.takela.common.spring.exception.AclException;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.servlet.HandlerMapping;

import java.io.IOException;
import java.util.List;

import static net.takela.acl.auth.consts.AclConsts.SESSION_USER_KEY;

public class AclCheckFilter implements Filter {
    private final AclService aclService;
    private final AclProperties aclProperties;
    private final AntPathMatcher antPathMatcher = new AntPathMatcher();
    public AclCheckFilter(AclService aclService, AclProperties aclProperties){
        this.aclService = aclService;
        this.aclProperties = aclProperties;
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        boolean isAnonymous = aclProperties.getAnonymousUrls() != null && aclProperties.getAnonymousUrls().stream().anyMatch( url -> antPathMatcher.match(url, request.getRequestURI()) );

        if (isAnonymous){
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }

        //如果限定角色
        AclUser user = (AclUser)request.getAttribute(SESSION_USER_KEY);
        if (user == null){
            throw new AclException("acl.error", request.getRequestURI());
        }
        //判断是否拥有路由权限
        String route = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
        List<UserRole> roles = aclService.getUserRoles(user.getUid());
        user.setRoles( roles);
        boolean isAuth = aclService.hasRouteRights(roles,route);
        if (!isAuth){
            throw new AclException("acl.error",request.getRequestURI());
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }
}
